#include <dspSimulator/instruction/dadd.h>

bool DADD::checkCondition(std::shared_ptr<DspMachine> dspMachine) {
    return checkStandardCondition(dspMachine);
}

void DADD::loadInstIRIntoJit(llvm::LLVMContext *llvmContext, llvm::Module *module,
                             std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
}

std::shared_ptr<Instruction> DADD::decode(std::shared_ptr<InstInfo> instInfo, u64 baseCycle) {
    std::shared_ptr<DADD> dadd;
    auto dspInstInfo = std::dynamic_pointer_cast<DspInstInfo>(instInfo);
    bool isStandardInst = dspInstInfo->isStandardInstruction();
    if (isStandardInst) {
        auto data = vectorToBitSet<32>(dspInstInfo->getBits());
        if (checkBits<10>(data, 2, 0b1000011000) && existStandardCondition(data)) {
            dadd = std::make_shared<DADD>(dspInstInfo->getAddress(), baseCycle);
            dadd->creg_z = extractBits<4>(data, 28);
            dadd->dst = extractBits<5>(data, 23).to_ulong();
            dadd->src2 = extractBits<5>(data, 18).to_ulong();
            dadd->cst = extractBits<5>(data, 13).to_ulong();
            dadd->x = data[12];
            dadd->s = data[1];
            dadd->p = data[0];
            if (dadd->s == 0) {
                dadd->funcUnit = FuncUnit::S1;
            } else {
                dadd->funcUnit = FuncUnit::S2;
            }
            dadd->instFormat = InstFormat::Kind1;
        } else if (checkBits<10>(data, 2, 0b0100010110) && existStandardCondition(data)) {
            dadd = std::make_shared<DADD>(dspInstInfo->getAddress(), baseCycle);
            dadd->creg_z = extractBits<4>(data, 28);
            dadd->dst = extractBits<5>(data, 23).to_ulong();
            dadd->src2 = extractBits<5>(data, 18).to_ulong();
            dadd->cst = extractBits<5>(data, 13).to_ulong();
            dadd->x = data[12];
            dadd->s = data[1];
            dadd->p = data[0];
            if (dadd->s == 0) {
                dadd->funcUnit = FuncUnit::L1;
            } else {
                dadd->funcUnit = FuncUnit::L2;
            }
            dadd->instFormat = InstFormat::Kind1;
        }
    }
    return dadd;
}

void DADD::executeCustom(std::shared_ptr<TargetMachine> targetMachine, ExecutePhase executePhase) {
    if (instFormat == InstFormat::Kind1) {
        u64 scst = static_cast<u64>(extractBitsAndToInt<5>(cst));
        u64 src2 = static_cast<u64>(*src2LoRegPtr) + (static_cast<u64>(*src2HiRegPtr) << 32);
        u64 res = scst + src2;
        u32 lo = static_cast<u32>(res & 0xffffffff);
        u32 hi = static_cast<u32>((res & 0xffffffff00000000) >> 32);
        *dstLoRegPtr = lo;
        *dstHiRegPtr = hi;
    }
}

std::string DADD::toString() const {
    std::string res;
    if (!isCompactInstruction) {
        res += getStandardConditionString() + " ";
    }
    res += m_name + " " + FuncUnitName[static_cast<u32>(funcUnit)] + " ";
    if (instFormat == InstFormat::Kind1) {
        res += std::to_string(extractBitsAndToInt<5>(cst)) + "," + getSrc2Reg64Name() + "," + getDstReg64Name();
    }
    return res;
}

std::shared_ptr<DspInstruction> DADD::clone() {
    return std::make_shared<DADD>(*this);
}

